#include <Windows.h>
#include <tchar.h>
#include <stdio.h>

#define IDC_BTNINSTALL					0X1001
#define IDC_BTNUNINSTALL				0X1002
#define IDC_BTNEXIT						0X1003

void RunMessageLoop()
{
	MSG msg;

	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	return;
}

void CreateWnd(const TCHAR* szClassName, const TCHAR* szAppName)
{
	WNDCLASS wcs;
	if (FALSE != GetClassInfo(GetModuleHandle(NULL), szClassName, &wcs))
	{
		HWND hWnd = CreateWindow(szClassName, szAppName, WS_VISIBLE|WS_OVERLAPPEDWINDOW, 0, 0, 800, 480, NULL, NULL, NULL, 0);
		if (NULL != hWnd && IsWindow(hWnd))
		{
			ShowWindow(hWnd, SW_SHOW);
			UpdateWindow(hWnd);
		}
	}

	return;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
	typedef BOOL (*ACTIVEHOOK)(HWND, HWND);
	typedef BOOL (*DEACTIVEHOOK)();

	static HMODULE hModule = NULL;
	switch (nMsg)
	{
		case WM_CREATE:
		{
			struct SCtrlInfo {
				const TCHAR*	szTitle;
				UINT			nID;
			};

			SCtrlInfo CtrlInfoList[] = {
				{_T("Install Hook"), IDC_BTNINSTALL}, {_T("Uninstall Hook"), IDC_BTNUNINSTALL}, {_T("Exit App"), IDC_BTNEXIT},
			};

			int x	= 0;
			int y	= 0;
			int cx	= 120;
			int cy	= 40;
			for (int ii = 0; ii < sizeof(CtrlInfoList)/sizeof(*CtrlInfoList); ii++)
			{
				CreateWindow(_T("Button"), CtrlInfoList[ii].szTitle, WS_VISIBLE|WS_CHILD, x, y, cx, cy, hWnd, (HMENU)CtrlInfoList[ii].nID, NULL, 0);
				x += cx + 10;
			}
			
			break;
		}
		case 100:
		{
			static int nCount = 0;
			TCHAR szTmp[MAX_PATH];
			_stprintf(szTmp, _T("<%05d> Message: 0x%0X  wParam: ox%0X\n"), ++nCount, wParam, lParam);
			OutputDebugString(szTmp);

			break;
		}
		case WM_COMMAND:
		{
			switch (LOWORD(wParam))
			{
				case IDC_BTNINSTALL:
				{	
					const TCHAR* szFileName = _T("MSGTracker.dll");
					TCHAR szDLLPath[MAX_PATH];
					GetModuleFileName(GetModuleHandle(NULL), szDLLPath, MAX_PATH);
					TCHAR* pChr = _tcsrchr(szDLLPath, _T('\\'));
					if (pChr != NULL) pChr[1] = _T('\0');
					_tcscat(szDLLPath, szFileName);
					if (-1 != GetFileAttributes(szDLLPath))
					{
						hModule = LoadLibrary(szDLLPath);
						if (NULL != hModule)
						{
							ACTIVEHOOK fnActiveHook = (ACTIVEHOOK)GetProcAddress(hModule, ("ActiveHook"));
							if (NULL != fnActiveHook)
							{
								HWND hNotePadWnd = FindWindowEx(NULL, NULL, _T("Notepad"), NULL);
								if (NULL != hNotePadWnd)
								{
									fnActiveHook(hNotePadWnd, hWnd);
								}							
							}
						}
					}
					break;
				}
				case IDC_BTNUNINSTALL:
				{
					if (NULL != hModule)
					{
						DEACTIVEHOOK fnDeactiveHook = (DEACTIVEHOOK)GetProcAddress(hModule, ("DeactiveHook"));
						if (NULL != fnDeactiveHook)
						{
							fnDeactiveHook();
						}
						FreeLibrary(hModule);
						hModule	= NULL;
					}
					
					break;
				}
				case IDC_BTNEXIT:
				{	
					DestroyWindow(hWnd);
					break;
				}
				default:
					break;
			}
			break;
		}
		case WM_PAINT:
			{
				PAINTSTRUCT ps;
				HDC hDC = BeginPaint(hWnd, &ps);

				EndPaint(hWnd, &ps);
				break;
			}
		case WM_DESTROY:
		{
			PostQuitMessage(0);
			break;
		}
	}

	return DefWindowProc(hWnd, nMsg, wParam, lParam);
}


bool RegisterWndClass(const TCHAR* szClassName)
{
	WNDCLASS wcs		= {0};
	wcs.cbClsExtra		= 0;
	wcs.style			= CS_HREDRAW|CS_VREDRAW;
	wcs.hbrBackground	= (HBRUSH)GetStockObject(WHITE_BRUSH);
	wcs.lpszClassName	= szClassName;
	wcs.hCursor			= (HCURSOR)LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
	wcs.hInstance		= GetModuleHandle(NULL);
	wcs.lpfnWndProc		= WndProc;
	wcs.hIcon			= (HICON)LoadIcon(NULL, IDI_APPLICATION);

	return (0 != RegisterClass(&wcs));
}


BOOL WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPreInstance, LPTSTR szCmdLine, int nShowCmd)
{
	const TCHAR* szClassName	= _T("Win32App");
	const TCHAR* szAppName		= _T("Demo0054");
	
	if (RegisterWndClass(szClassName))
	{
		CreateWnd(szClassName, szAppName);
		RunMessageLoop();
	}

	return 0;
}